package bancosys.tec.security.impl.web.servlet;

import java.io.IOException;

import javax.security.auth.Subject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;

import bancosys.tec.security.impl.web.WebSecurityContext;

/**
 * Servlet responsável pelo login. Efetua o login e redireciona o usuario para o URI presente o PathInfo. Configurações:<br>
 * <table>
 * <tr>
 * <td><code>loginErrorPage</code></td>
 * <td>URI da página de "permission denied".</td>
 * </tr>
 * <tr>
 * <td><code>defaultSuccessPage</code></td>
 * <td>URI da página padrão para onde o usuário deve ser enviado após efetuar corretamente o login.</td>
 * </tr>
 * <tr>
 * <td>outras configurações</td>
 * <td>ver configs herdados do {@link SecurityServlet}</td>
 * </tr>
 * </table>
 * 
 * @created 19/03/2008
 * @author Gustavo Almeida
 */
public class LoginServlet extends SecurityServlet {

    private static final Logger LOG = Logger.getLogger(LoginServlet.class);

    private static final String LOGIN_ERROR_PAGE = "loginErrorPage";

    private static final String LOGIN_ERROR_MESSAGE = "loginErrorMessage";

    private static final String DEFAULT_SUCCESS_PAGE = "defaultSuccessPage";

    public static final String USERNAME_PARAM = "j_username";

    public static final String PASSWORD_PARAM = "j_password";

    private String defaultSuccessPage;

    private String loginErrorPage;

    /**
     * Inicializa o servlet lendo os parametros de configuração.
     * 
     * @throws ServletException veja {@link SecurityServlet#init()}
     */
    @Override
    public void init() throws ServletException {
        super.init();
        this.loginErrorPage =
                this.getNotNull(this.getServletConfig().getInitParameter(LOGIN_ERROR_PAGE), bancosys.tec.security.SecurityURLMapping
                        .getInstance().getUnauthorizedURL());
        this.defaultSuccessPage = this.getNotNull(this.getServletConfig().getInitParameter(DEFAULT_SUCCESS_PAGE), "/");
    }

    /**
     * Delega para {@link #doPost(HttpServletRequest, HttpServletResponse)}
     * 
     * @param request request http.
     * @param response resposta http.
     * @throws ServletException e
     * @throws IOException e
     * @see #doPost(HttpServletRequest, HttpServletResponse)
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        LOG.warn("Processando login com método GET.");
        this.doPost(request, response);
    }

    /**
     * Processa o login
     * 
     * @param request request http.
     * @param response resposta http.
     * @throws ServletException e
     * @throws IOException e
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = this.getUserName(request);
        String password = this.getPassword(request);
        String pathInfo = this.login(request, response, username, password);
        this.setNoCacheHeaders(response);
        response.sendRedirect(pathInfo);
    }

    /**
     * Obtem o password digitado
     * 
     * @param request {@link HttpServletRequest}
     * @return o password digitado
     */
    protected String getPassword(HttpServletRequest request) {
        return request.getParameter(PASSWORD_PARAM);
    }

    /**
     * Obtem o usuario digitado
     * 
     * @param request {@link HttpServletRequest}
     * @return o usuario digitado
     */
    protected String getUserName(HttpServletRequest request) {
        return request.getParameter(USERNAME_PARAM);
    }

    /**
     * Executa o login e devolve a página para onde o usuário deve ser redirecionado.
     * 
     * @param request request http.
     * @param response response http
     * @param username nome do usuário.
     * @param password senha.
     * @return uri da página para onde o usuário deve ser redirecionado.
     */
    private String login(HttpServletRequest request, HttpServletResponse response, String username, String password) {
        try {
            WebSecurityContext context = new WebSecurityContext(request, response);
            Subject subject = this.getSecurityManager().login(username, password, context);
            if (subject == null) {
                return request.getContextPath() + this.loginErrorPage;
            } else {
                this.getSecurityManager().storeSubject(context, subject);
                this.afterLogin(request, subject);
                if (request.getPathInfo() != null) {
                    return request.getPathInfo();
                } else {
                    return request.getContextPath() + this.defaultSuccessPage;
                }
            }
        } catch (bancosys.tec.security.SecurityException e) {
            HttpSession session = request.getSession();
            if (session != null) {
                session.setAttribute(LOGIN_ERROR_MESSAGE, e.getMessage());
            }
            return request.getContextPath() + this.loginErrorPage;
        }
    }

    /**
     * hook para executar tarefas após o login. O subject não está em thread local.
     * 
     * @param request request http.
     * @param subject subject.
     */
    protected void afterLogin(HttpServletRequest request, Subject subject) {
        // hook para executar tarefas após o login.
    }
}
